package org.test4j;

import org.test4j.mock.functions.Executor;

import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

/**
 * 单例, 存储测试过程中全局数据
 *
 * @author darui.wu
 */
public final class Context {
    /**
     * 进入mocking zone的层数
     */
    private static final AtomicInteger noMockingCount = new AtomicInteger(0);

    private static ThreadLocal<Class> currTestClass = new InheritableThreadLocal<>();

    private static ThreadLocal<Object> currTestObject = new InheritableThreadLocal<>();

    private static ThreadLocal<Method> currTestMethod = new InheritableThreadLocal<>();

    private Context() {
    }

    /**
     * 是否在No Mocking区域
     *
     * @return
     */
    public static boolean isInsideNoMockingZone() {
        return noMockingCount.get() > 0;
    }

    /**
     * supplier执行过程中mock失效
     *
     * @param supplier
     * @param <T>
     * @return
     */
    public static <T> T enterNoMocking(Supplier supplier) {
        try {
            noMockingCount.incrementAndGet();
            return (T) supplier.get();
        } finally {
            noMockingCount.decrementAndGet();
        }
    }

    /**
     * executor执行过程中mock失效
     *
     * @param executor
     */
    public static void enterNoMocking(Executor executor) {
        try {
            noMockingCount.incrementAndGet();
            executor.execute();
        } finally {
            noMockingCount.decrementAndGet();
        }
    }

    /**
     * 重置no mocking zone
     */
    public static void clearNoMockingZone() {
        noMockingCount.set(0);
    }

    public static Class currTestClass() {
        return currTestClass.get();
    }

    public static void currTestClass(Class testClass) {
        currTestClass.set(testClass);
    }

    public static Object currTestObject() {
        return currTestObject.get();
    }

    public static void currTestObject(Object testObject) {
        currTestObject.set(testObject);
    }

    public static void currTestMethod(Method method) {
        currTestMethod.set(method);
    }

    public static Method currTestMethod() {
        return currTestMethod.get();
    }
}